package com.stars.module.login.service.impl;

import com.stars.base.constants.RedisConstants;
import com.stars.base.constants.SystemSettingConstants;
import com.stars.util.cache.CacheUtil;
import com.stars.util.common.DevelopKit;
import com.stars.util.jwt.JWTUtil;
import com.stars.util.jwt.JwtToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * @author : Rocks
 * @version : 1.0
 * @date : 2022/11/22 19:45
 * @description : 认证方式
 */
@Component
public class StarsRealm extends AuthorizingRealm {

    private final CacheUtil cacheUtil;

    public StarsRealm(CacheUtil cacheUtil) {
        this.cacheUtil = cacheUtil;
    }

    /*
     * 多重写一个support
     * 标识这个Realm是专门用来验证JwtToken，不负责验证其他的token（UsernamePasswordToken）
     * 必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }


    /**
     * Shiro 认证操作
     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可
     *
     * @param token 就是从过滤器中传入的jwtToken

     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String credentials = (String) token.getCredentials();

        String sessionId = JWTUtil.getClaim(credentials, "sessionId");
        if(!StringUtils.hasLength(sessionId)){
            throw new AuthenticationException("token解析异常");
        }

        Object obj = cacheUtil.getValue(false,RedisConstants.SESSION_PREFIX+sessionId);
        if(obj==null){
            throw new AuthenticationException("session失效，请重新登录");
        }
        String onLineTime = DevelopKit.getStringFromDBConfig(SystemSettingConstants.SYS_ONLINE_TIME, RedisConstants.DEFAULT_ONLINE);

        cacheUtil.expire(false,RedisConstants.SESSION_PREFIX+sessionId , Long.parseLong(onLineTime));

        return new SimpleAuthenticationInfo(sessionId,credentials,"StarsRealm");
    }

    /**
     * Shiro授权操作
     * 只有当需要检测用户权限的时候才会调用此方法，例如Controller层方法有Shiro权限注解
     * 使用userID去数据库中查找到对应的权限，然后将权限赋值给这个用户就可以实现权限的认证了
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //暂不编写，此处编写后，controller中可以使用@RequiresPermissions来对用户权限进行拦截
        return new SimpleAuthorizationInfo();
    }
}
